home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / exampleCode / inventor / noodle / NurbMaker.c++ < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  12.1 KB  |  398 lines

  1. /*
  2.  * Copyright (C) 1994, Silicon Graphics, Inc.
  3.  * All Rights Reserved.
  4.  *
  5.  * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  6.  * the contents of this file may not be disclosed to third parties, copied or
  7.  * duplicated in any form, in whole or in part, without the prior written
  8.  * permission of Silicon Graphics, Inc.
  9.  *
  10.  * RESTRICTED RIGHTS LEGEND:
  11.  * Use, duplication or disclosure by the Government is subject to restrictions
  12.  * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  13.  * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  14.  * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  15.  * rights reserved under the Copyright Laws of the United States.
  16.  */
  17. /*
  18. |   Description:
  19. |      Defines the NurbMaker class. Given a quadMesh,
  20. |      a bunch of parameters, it creates a group node with a bunch
  21. |      of SoIndexedNurbsSurface nodes. These nodes will create a nurbs
  22. |      surface if placed after an SoCoordinate3 node with the number of
  23. |      points specified by the QuadMesh node.
  24. |
  25. |      Note that you only need to look at the SoCoordinate3 node if
  26. |      you need to figure out whether edges match for wraparound.
  27. |      Otherwise this is all strictly 'topological'
  28. |
  29. |   Author(s)          : Paul Isaacs
  30. */
  31.  
  32.  
  33.  
  34. #include <Inventor/nodes/SoCoordinate3.h>
  35. #include <Inventor/nodes/SoGroup.h>
  36. #include <Inventor/nodes/SoQuadMesh.h>
  37. #include <Inventor/nodes/SoIndexedNurbsSurface.h>
  38.  
  39. #include "NurbMaker.h"
  40.  
  41. // These knot vectors are used to make CUBIC_TO_EDGE splines
  42. // meet up with the mesh edge.
  43.  
  44. static float cubicInteriorKnots[8]      = { 0, 1, 2, 3, 4, 5, 6, 7 };
  45.  
  46. static float cubic2FromLateEdgeKnots[8] = { 0, 1, 2, 3, 4, 5, 6, 6 };
  47. static float cubic1FromLateEdgeKnots[8] = { 0, 1, 2, 3, 4, 5, 5, 5 };
  48. static float cubic0FromLateEdgeKnots[8] = { 0, 1, 2, 3, 4, 4, 4, 4 };
  49.  
  50. static float cubic2FromEarlyEdgeKnots[8] = { 0, 0, 1, 2, 3, 4, 5, 6 };
  51. static float cubic1FromEarlyEdgeKnots[8] = { 0, 0, 0, 1, 2, 3, 4, 5 };
  52. static float cubic0FromEarlyEdgeKnots[8] = { 0, 0, 0, 0, 1, 2, 3, 4 };
  53.  
  54. // Creates group with new SoIndexedNurbsSurface nodes underneath.
  55. SoGroup *
  56. NurbMaker::createNurbsGroup( SoQuadMesh *quadNode, SoCoordinate3 *coordNode )
  57. {
  58.     SbBool rowsMatch = FALSE;
  59.     SbBool colsMatch = FALSE;
  60.  
  61.     int vPerCol = (int) quadNode->verticesPerColumn.getValue();
  62.     int vPerRow = (int) quadNode->verticesPerRow.getValue();
  63.  
  64.     SbVec2s quadMeshDivs( vPerRow, vPerCol );
  65.  
  66.     // Only bother checking if we're wrapping.
  67.     if (coordNode != NULL && myWrap[0] == TRUE) {
  68.     rowsMatch = TRUE;
  69.         // Test if first and last row are the same.
  70.     for (int topInd = 0, botInd = vPerRow * (vPerCol - 1);
  71.          topInd < vPerRow; topInd++, botInd++ ) {
  72.          if (  coordNode->point[topInd] != coordNode->point[botInd] ) {
  73.         rowsMatch = FALSE;
  74.          }
  75.     }
  76.     }
  77.     if (coordNode != NULL && myWrap[1] == TRUE) {
  78.     SbBool colsMatch = TRUE;
  79.         // Test if first and last col are the same.
  80.     for (int leftInd = 0, rightInd = vPerRow - 1;
  81.          leftInd < vPerRow * (vPerCol - 1); 
  82.          leftInd += vPerRow, rightInd += vPerRow) {
  83.          if (  coordNode->point[leftInd] != coordNode->point[rightInd] ) {
  84.         colsMatch = FALSE;
  85.          }
  86.     }
  87.     }
  88.  
  89.     return ( createNurbsGroup( quadMeshDivs, SbVec2s(rowsMatch,colsMatch )));
  90. }
  91.  
  92. // Creates group with new SoIndexedNurbsSurface nodes underneath.
  93. SoGroup *
  94. NurbMaker::createNurbsGroup( SbVec2s numQuadMeshDivisions, 
  95.                  SbVec2s doEdgesMatch )
  96. {
  97.     establishMyKnotParams();
  98.     // The patch size is the number of control points on the side
  99.     // of each patch. It's determined by the number of knots and order
  100.     SbVec2s patchSize = myNumKnots - myOrder;
  101.  
  102.     // Make a group to put the new NURBS under
  103.     if (nurbsGroup != NULL)
  104.     nurbsGroup->unref();
  105.  
  106.     nurbsGroup = new SoGroup;
  107.     nurbsGroup->ref();
  108.  
  109.     // What are the mesh dimensions?
  110.     int vPerRow = (int) numQuadMeshDivisions[0];
  111.     int vPerCol = (int) numQuadMeshDivisions[1];
  112.  
  113.     // Determine last row and last column that we can use for our 
  114.     // upper left corner of our little patch.
  115.     // Initially, figure that the last patch's right/bottom edge
  116.     // need to line up with the mesh's right/bottom edge.
  117.     int lastRowToDo = vPerCol - patchSize[1];
  118.     int lastColToDo = vPerRow - patchSize[0];
  119.  
  120.     // If we don't wrap, all rows and columns are used.
  121.     // If we are wrapping and the first&last row/column are the same,
  122.     // then we will never use the last row/column.
  123.     int numUseableRows = vPerCol;
  124.     int numUseableCols = vPerRow;
  125.  
  126.     // If we're wrapping rows, the last patch left edge is the same as the
  127.     // mesh's right edge.
  128.     // But if the left and right edges of the mesh are identical, we don't
  129.     // need to repeat the set of patches that uses the mesh's right edge as 
  130.     // their own (the patches' own) left edge.
  131.     if (myWrap[0] == TRUE) {
  132.     if (doEdgesMatch[0]) {
  133.         lastRowToDo = vPerCol - 2;
  134.         numUseableRows = vPerCol - 1;
  135.     }
  136.     else {
  137.         lastRowToDo = vPerCol - 1;
  138.         numUseableRows = vPerCol;
  139.     }
  140.     }
  141.  
  142.     // If we're wrapping cols, the last patch top edge is the same as the
  143.     // mesh's bottom edge.
  144.     // But if the top and bottom edges of the mesh are identical, we don't
  145.     // need to repeat the set of patches that uses the mesh's bottom edge as 
  146.     // their own (the patches' own) top edge.
  147.     if (myWrap[1] == TRUE) {
  148.     if (doEdgesMatch[1]) {
  149.         lastColToDo = vPerRow - 2;
  150.             numUseableCols = vPerRow - 1;
  151.     }
  152.     else {
  153.         lastColToDo = vPerRow - 1;
  154.         numUseableCols = vPerRow;
  155.     }
  156.     }
  157.  
  158.     // In each patch, we will lay down the coordinate indices as either 
  159.     // increasing from left to right , as in:
  160.     //   0  1  2  3
  161.     //   4  5  6  7
  162.     //   8  9 10 11 
  163.     //  12 13 14 15
  164.     //
  165.     // or increasing from right to left, depending on 'flipNormals'
  166.     //   3  2  1  0
  167.     //   7  6  5  4
  168.     //  11 10  9  8
  169.     //  15 14 13 12
  170.     int numPatchInds = patchSize[0] * patchSize[1];
  171.     int *patchInds = new int [ numPatchInds ];
  172.     if ( flipNormals == FALSE ) {
  173.     for (int i = 0, count=0; i < patchSize[1]; i++ ){
  174.         for(int j = 0; j < patchSize[0]; j++ ) {
  175.         patchInds[count] = (i * patchSize[0]) + j;
  176.         count++;
  177.         }
  178.     }
  179.     }
  180.     else for (int i = 0, count=0; i < patchSize[1]; i++ ){
  181.         for(int j = patchSize[0]-1; j >=0; j--) {
  182.         patchInds[count] = (i * patchSize[0]) + j;
  183.         count++;
  184.         }
  185.     }
  186.  
  187.     // Now, create the patches. Each is a nurb with 
  188.     // a patchSize[0]by patchSize[1] control point patch.
  189.     // The knots are as already established.
  190.     for ( int row = 0; row <= lastRowToDo; row+= myShift[0] ) {
  191.     for ( int col = 0; col <= lastColToDo; col+= myShift[1] ) {
  192.  
  193.         // Create the NURB and set the easy fields...
  194.         SoIndexedNurbsSurface *myNurb = new SoIndexedNurbsSurface;
  195.         nurbsGroup->addChild(myNurb);
  196.         myNurb->numUControlPoints = patchSize[0];
  197.         myNurb->numVControlPoints = patchSize[1];
  198.         if ( patchType != CUBIC_TO_EDGE) {
  199.         myNurb->uKnotVector.setValues(0,myNumKnots[0],myUKnots);
  200.         myNurb->vKnotVector.setValues(0,myNumKnots[1],myVKnots);
  201.         }
  202.         else {
  203.         applyCubicToEdgeKnotVectors(row, col, myNurb, 
  204.                         lastRowToDo, lastColToDo);
  205.         }
  206.  
  207.         for (int pRow = 0,count = 0; pRow < patchSize[1]; pRow++ ) {
  208.  
  209.         // Now we've got to set up the indices. Determine the row 
  210.         // number in the quadmesh (0<=value<numUseableRows)
  211.         // to use as the row number in the patch( 0<=pRow<patchSize[1])
  212.         int rowInQuadMesh = row + pRow;
  213.  
  214.         // Now check to see if we need to wraparound this row.
  215.         if (rowInQuadMesh >= numUseableRows)
  216.             rowInQuadMesh -= numUseableRows;
  217.  
  218.         for (int pCol = 0; pCol < patchSize[0]; pCol++ ) {
  219.  
  220.             // Determine the col number in the mesh 
  221.             // (0<=value<numUseableCols) to use as the col number 
  222.             // in the patch( 0<=pRow<patchSize[0])
  223.             int colInQuadMesh = col + pCol;
  224.  
  225.             // Now check to see if we need to wraparound this column.
  226.             if (colInQuadMesh >= numUseableCols)
  227.             colInQuadMesh -= numUseableCols;
  228.  
  229.  
  230.             myNurb->coordIndex.set1Value( patchInds[count], 
  231.                 rowInQuadMesh * vPerRow + colInQuadMesh);
  232.  
  233.             count++;
  234.         }
  235.         }
  236.     }
  237.     }
  238.  
  239.     return nurbsGroup;
  240. }
  241.  
  242. NurbMaker::NurbMaker()
  243. {
  244.     nurbsGroup = NULL;
  245.  
  246.     patchType  = CUBIC_TO_EDGE;
  247.  
  248.     myNumKnots.setValue(0,0);
  249.     myUKnots    = myVKnots    = NULL;
  250.     myOrder.setValue(4,4);
  251.     myShift.setValue(1,1);
  252.     myWrap.setValue(0,0);
  253.  
  254.     userNumKnots.setValue(0,0);
  255.     userUKnots    = userVKnots    = NULL;
  256.     userOrder.setValue(4,4);
  257.  
  258.     flipNormals = FALSE;
  259. }
  260.  
  261. NurbMaker::~NurbMaker()
  262. {
  263.     if (nurbsGroup) {
  264.     nurbsGroup->unref();
  265.         nurbsGroup = NULL;
  266.     }    
  267. }
  268.  
  269. void
  270. NurbMaker::establishMyKnotParams()
  271. {
  272.     int i;
  273.  
  274.     // Take care of knot array allocation.
  275.     if (    patchType == BEZIER || patchType == CUBIC 
  276.      || patchType == CUBIC_TO_EDGE ) {
  277.     if ( myNumKnots[0] != 8 ) {
  278.         if (myUKnots != NULL) delete []myUKnots;
  279.         myNumKnots[0] = 8;
  280.         myUKnots    = new float[8];
  281.     }
  282.     if ( myNumKnots[1] != 8 ) {
  283.         if (myVKnots != NULL) delete []myVKnots;
  284.         myNumKnots[1] = 8;
  285.         myVKnots    = new float[8];
  286.     }
  287.     }
  288.     else {
  289.     if (myUKnots != NULL) delete []myUKnots;
  290.     if (myVKnots != NULL) delete []myVKnots;
  291.  
  292.     myNumKnots = userNumKnots;
  293.  
  294.     myUKnots    = new float[myNumKnots[0]];
  295.     myVKnots    = new float[myNumKnots[1]];
  296.     }
  297.  
  298.     // Take care of knot values and order values.
  299.     switch (patchType) {
  300.     case BEZIER:
  301.         myOrder.setValue(4,4);
  302.         for (i = 0; i < 4; i++)
  303.         myUKnots[i] = myVKnots[i] = 0;
  304.         for (i = 4; i < 8; i++)
  305.         myUKnots[i] = myVKnots[i] = 1;
  306.         break;
  307.     case CUBIC:
  308.     case CUBIC_TO_EDGE:
  309.         myOrder.setValue(4,4);
  310.         for (i = 0; i < 8; i++)
  311.         myUKnots[i] = myVKnots[i] = i;
  312.         break;
  313.     case USER_KNOTS:
  314.         myOrder    = userOrder;
  315.         for (i = 0; i < myNumKnots[0]; i++)
  316.         myUKnots[i] = userUKnots[i];
  317.         for (i = 0; i < myNumKnots[1]; i++) {
  318.         myVKnots[i] = userVKnots[i];
  319.         }
  320.         break;
  321.     }
  322. }
  323.  
  324. void
  325. NurbMaker::setUserKnots( SbVec2s newNumKnots,
  326.              float *newUKnots, float *newVKnots)
  327. {
  328.     userNumKnots = newNumKnots;
  329.     if (userUKnots == NULL)
  330.     delete [] userUKnots;
  331.     if (userVKnots == NULL)
  332.     delete [] userVKnots;
  333.     userUKnots = new float [userNumKnots[0]];
  334.     userVKnots = new float [userNumKnots[1]];
  335.     for (int i = 0; i < userNumKnots[0]; i++ )
  336.     userUKnots[i] = newUKnots[i];
  337.     for (int j = 0; j < userNumKnots[1]; j++ )
  338.     userVKnots[j] = newVKnots[j];
  339. }
  340.  
  341. void
  342. NurbMaker::getUserKnots( SbVec2s &numKnots,
  343.              float * UKnots, float * VKnots) 
  344. {
  345.     numKnots = userNumKnots;
  346.     if (UKnots == NULL)
  347.     delete [] UKnots;
  348.     if (VKnots == NULL)
  349.     delete [] VKnots;
  350.     UKnots = new float [userNumKnots[0]];
  351.     VKnots = new float [userNumKnots[1]];
  352.     for (int i = 0; i < userNumKnots[0]; i++ )
  353.     UKnots[i] = userUKnots[i];
  354.     for (int j = 0; j < userNumKnots[1]; j++ )
  355.     VKnots[j] = userVKnots[j];
  356. }
  357.  
  358. void 
  359. NurbMaker::setPatchType(PatchType newPatchType)
  360. {
  361.     patchType = newPatchType;
  362.     if (patchType == BEZIER) {
  363.     myShift.setValue(3,3);
  364.     }
  365.     else if (patchType == CUBIC || patchType == CUBIC_TO_EDGE) {
  366.     myShift.setValue(1,1);
  367.     }
  368. }
  369.  
  370. void
  371. NurbMaker::applyCubicToEdgeKnotVectors(int row, int col, 
  372.         SoIndexedNurbsSurface *myNurb, int lastRowToDo, int lastColToDo)
  373. {
  374.     float *uKs, *vKs;
  375.  
  376.     if ( myWrap[1] )               uKs = myUKnots;
  377.     else if (col == 0 )            uKs = cubic0FromEarlyEdgeKnots;
  378.     else if (col == lastColToDo)   uKs = cubic0FromLateEdgeKnots;
  379.     else if (col == 1 )            uKs = cubic1FromEarlyEdgeKnots;
  380.     else if (col == lastColToDo-1) uKs = cubic1FromLateEdgeKnots;
  381.     else if (col == 2 )            uKs = cubic2FromEarlyEdgeKnots;
  382.     else if (col == lastColToDo-2) uKs = cubic2FromLateEdgeKnots;
  383.     else                           uKs = myUKnots;
  384.  
  385.     if ( myWrap[0] )               vKs = myVKnots;
  386.     else if (row == 0 )            vKs = cubic0FromEarlyEdgeKnots;
  387.     else if (row == lastRowToDo)   vKs = cubic0FromLateEdgeKnots;
  388.     else if (row == 1 )            vKs = cubic1FromEarlyEdgeKnots;
  389.     else if (row == lastRowToDo-1) vKs = cubic1FromLateEdgeKnots;
  390.     else if (row == 2 )            vKs = cubic2FromEarlyEdgeKnots;
  391.     else if (row == lastRowToDo-2) vKs = cubic2FromLateEdgeKnots;
  392.     else                           vKs = myVKnots;
  393.  
  394.     myNurb->uKnotVector.setValues(0,8,uKs);
  395.     myNurb->vKnotVector.setValues(0,8,vKs);
  396.  
  397. };
  398.